﻿/*
   Open Intel 
   Copyright © 2011 – ISC. All Rights Reserved.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using Caliburn.Micro;
using ISC.RIM.Silverlight;
using OI.Async;
using OI.DataModel;
using OI.Events;

namespace OI.ViewModels
{
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class DatasetDetailsOptionsPanelViewModel : Screen,
                                                       IHandle<SelectDataset>,
                                                       IHandle<MapLayerRemoveFromList>,
                                                       IHandle<SaveState>,
                                                       IHandle<RestoreState>,
                                                       IHandle<DisplayRIMMap>,
                                                       IHandle<SelectMap>
    {
        #region DATA

        // visibility of panel bound by convention
        public enum Modes
        {
            Data,
            Map
        } ;

        private readonly IEventAggregator Events;
        private readonly IWindowManager WindowManager;
        public OIDataset CurrentDataset { get; set; }
        public Map RIMMap { get; private set; }
        

        public ISC.MapDotNetServer.Common.Maps.Map Map
        {
            get { return _Map; }
            set 
            { 
                _Map = value;
                NotifyOfPropertyChange(() => DownloadData);
            }
        }
        private ISC.MapDotNetServer.Common.Maps.Map _Map;

        // keep track of the mashup list
        public List<OIDataset> MashupList = new List<OIDataset>();
        private Modes _Mode = Modes.Data;

        // bound by convention
        public bool AddToMashup
        {
            get { return Mode == Modes.Map; }
        }


        // bound by convention
        public bool AccessFeeds
        {
            get { return Mode == Modes.Map; }
        }


        // count of mashup items text bound by convention
        public string MashupCountText
        {
            get { return MashupList.Count.ToString(); }
        }


        // bound via convention to stackpanel
        public bool DownloadData
        {
            get
            {
                return Map != null &&
                    (!Map.MetaData.ContainsKey(Configuration.SuppressDataDownloadMetaKey) ||
                     !Convert.ToBoolean(Map.MetaData[Configuration.SuppressDataDownloadMetaKey]));
            }
        }


        // bound via convention to text content
        public string DownloadDataText
        {
            get
            {
                if (Mode == Modes.Data)
                {
                    return "download CSV";
                }
                return "download shapefile";
            }
        }


        // bound via convention to text content
        public string AddToMashupText
        {
            get
            {
                OIDataset item;
                if (IsCurrentDatasetInMashup(out item))
                {
                    return "remove from my map";
                }
                return "add to my map";
            }
        }


        // which panel mode are we in
        public Modes Mode
        {
            get { return _Mode; }
            set
            {
                _Mode = value;
                NotifyOfPropertyChange(() => AddToMashup);
                NotifyOfPropertyChange(() => AddToMashupText);
                NotifyOfPropertyChange(() => DownloadDataText);
                NotifyOfPropertyChange(() => AccessFeeds);
            }
        }

        #endregion

        [ImportingConstructor]
        public DatasetDetailsOptionsPanelViewModel(IEventAggregator events, IWindowManager windowManager)
        {
            events.Subscribe(this);
            Events = events;
            WindowManager = windowManager;
        }


        protected override void OnViewLoaded(object view)
        {
            base.OnViewLoaded(view);
            Mode = Modes.Data;
        }

        #region FEEDS
        // we need to save the map to grab the extents for access 
        public void Handle(DisplayRIMMap message)
        {
            RIMMap = message.Map;
        }


        // we grab this to pass the current map layer displayed
        public void Handle(SelectMap message)
        {
            Map = message.Map;
        }


        // bound through CM action
        public void SelectAccessFeeds()
        {
            if (Map != null && RIMMap != null)
            {
                var vm = new FeedLinksViewModel(Map.Layers, RIMMap.MapView.GetMapExtents());
                WindowManager.ShowDialog(vm);
            }
        }

        #endregion

        #region MASHUP

        public void Handle(MapLayerRemoveFromList message)
        {
            string layerID = message.Layer.ID;
            OIDataset item = MashupList.FirstOrDefault((x) => x.LayerID == layerID);
            if (item != null)
            {
                MashupList.Remove(item);
                MashupListChange(false);
            }
        }


        // keep track of the currently active dataset
        public void Handle(SelectDataset message)
        {
            CurrentDataset = message.DataSet;
        }


        // add/remove the current dataset from the mashup list
        public void SelectAddRemItemsToMashup()
        {
            bool added = false;
            OIDataset item;

            if (IsCurrentDatasetInMashup(out item))
            {
                MashupList.Remove(item);
            }
            else if (CurrentDataset != null)
            {
                MashupList.Add(CurrentDataset);
                added = true;
            }

            MashupListChange(added);
        }


        // removing an MDN layer from the map layers needs to also remove the dataset from the mashup list
        private void MashupListChange(bool added)
        {
            NotifyOfPropertyChange(() => MashupCountText);
            NotifyOfPropertyChange(() => AddToMashupText);

            // fire off event of mashup list change
            Events.Publish(new ChangeMashupList
                               {
                                   MashupList = MashupList,
                                   Added = added
                               });
        }


        // return true if a Dataset is in the mashup with the same layer id
        private bool IsCurrentDatasetInMashup(out OIDataset item)
        {
            item = null;
            if (CurrentDataset == null)
            {
                return false;
            }
            item = MashupList.FirstOrDefault((x) => x.LayerID == CurrentDataset.LayerID);
            return item != null;
        }

        #endregion


        #region DOWNLOAD

        // handle the download CSV and Shapefile
        public void SelectDownloadData()
        {
             Coroutine.BeginExecute(DownloadDataIterator());
        }


        public IEnumerator<IResult> DownloadDataIterator()
        {
            Stream pkgStream = null;
            Events.Publish(new ShowBusy { Caption = "packaging your data for download, this may take a minute..." });

            var dp = new DataPackage(Mode, CurrentDataset.TableName);
            yield return dp;

            // if we got data back
            if (dp.Results != null)
            {
                pkgStream = new MemoryStream( dp.Results );
            }

            Events.Publish(new HideBusy());

            // we need this indirection in order to use SaveFileDialog (it requires user interation)
            if (pkgStream != null)
            {
                var vm = new DownloadReadyViewModel(pkgStream, Mode);
                WindowManager.ShowDialog(vm);
            }
        }

        #endregion


        #region SHARE


        public void Handle(RestoreState message)
        {
            string stateStr = message.Read(GetType().ToString());
            var mulst = MessageSerializer.Deserialize<List<OIDataset>>(stateStr);

            if (mulst != null)
            {
                MashupList = mulst;

                NotifyOfPropertyChange(() => MashupCountText);
                NotifyOfPropertyChange(() => AddToMashupText);

                // fire off event of mashup list change
                Events.Publish(new ChangeMashupList
                {
                    MashupList = MashupList,
                    Added = true
                });
            }
        }


        public void Handle(SaveState message)
        {
            // json serialize
            string stateStr = MessageSerializer.Serialize(MashupList);

            // write to state
            message.Write(GetType().ToString(), stateStr);
        }

        #endregion
    }
}